package de.gameduell.net.src.connection {
	import de.gameduell.net.src.communication.Communication;	
	
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.net.XMLSocket;
	import flash.utils.Timer;
	
	import de.gameduell.framework.debug.Debug;
	import de.gameduell.net.src.communication.CommunicationEvent;
	import de.gameduell.net.src.communication.ICommunication;
	import de.gameduell.net.src.communication.ServerMessageEvent;
	import de.gameduell.net.src.message.IMessage;
	import de.gameduell.net.src.protocol.CommunicationRequests;	

	public class SocketConnection extends XMLSocket implements IConnection {
		
		public static const CONNECTION_TYPE:String = "socket";
			
		private const TYPE:String = "flashsocket-v3";
		private const TIMEOUT:int = 5000;
		
		private var communication:ICommunication;
		private var synchronisation:Synchronisation;
		private var timeOutTimer:Timer;
		private var _used:Boolean = false;
		
		public function SocketConnection(aCommunication:ICommunication,synctime:int) {
			communication   = aCommunication;
			synchronisation = Synchronisation.getInstance();
			synchronisation.init(communication,synctime);
			timeOutTimer = new Timer(TIMEOUT);
			timeOutTimer.addEventListener(TimerEvent.TIMER, onTimeOut);
			addEventListener(Event.CONNECT, onConnected);
			communication.addEventListener(CommunicationRequests.SOCKET, socketConnected);
		}
		
		override public function close():void{
			synchronisation.close();
			super.close();
		}
		
		private function onTimeOut(event:TimerEvent):void {
			log("onTimeOut: ", Debug.CONNECTION);
			removeEventListener(Event.CONNECT, onConnected);
			timeOutTimer.stop();
			dispatchEvent(new CommunicationEvent(CommunicationEvent.TIMEOUT));
		}

		override public function connect(host:String, port:int):void{
			log("connect: " + host + ":"+ port, Debug.CONNECTION);
			timeOutTimer.stop();
			timeOutTimer.start();
			addEventListener(DataEvent.DATA,onData);
			try{
				super.connect(host,port);
			}catch(e:Error){
				log("connect: " + e, Debug.ERROR);
			}
		}
		
		private function onData(event:DataEvent):void {
			_used = true;
			removeEventListener(DataEvent.DATA,onData);
		}

		private function socketConnected(event:ServerMessageEvent):void {
			log("socketConnected");
			synchronisation.sync();
			dispatchEvent(new CommunicationEvent(CommunicationEvent.CONNECTED));		
		}

		public function sendMessage(message:IMessage):void {	
			// update sync message before sending
			if(message.requestType == CommunicationRequests.SYNC){
				message = synchronisation.updateSyncMessage(message);
			}
			try{
				log("send message: " + TYPE + message.content, Debug.SEND);
				send(TYPE + message.encryptedContent);
			}catch(e:Error){
				log("send message: exception: " + e + " content: " + message.content, Debug.ERROR);
			}
		}
		
		private function onConnected(event:Event):void{
			log("onConnected - XMLSocket is now connected.", Debug.CONNECTION);
			timeOutTimer.stop();
			communication.send(CommunicationRequests.SOCKET, new Array());
		}
		
		public function stopConnectTimer():void {
			timeOutTimer.stop();
		}
		
		public function getType():String {
			return CONNECTION_TYPE;
		}
		
		public function reconnect(host:String, port:int):void {
			addEventListener(Event.CONNECT, onConnected);
			connect(host, port);
		}
		
		public function get used():Boolean {
			return _used;
		}
		
		private function log(aMessage:String, logMode:String = Debug.DEBUG):void{
			if(Communication.DEBUG_ENABLED || logMode == Debug.ERROR){
				Debug.trace("SocketConnection::" +  aMessage, logMode);
			}
		} 
	}
}
